﻿using FRMS.BUS;
using FRMS.DAL;
using FRMS.Model;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FRMS.WebSockets
{
    public class DeviceWebSocketMiddleware
    {
        public static List<ClientSocket> clientSockets = new List<ClientSocket>();
        public static List<SocketList> _sockets = new List<SocketList>();
        private readonly RequestDelegate _next;
        public static List<DeviceStateInfo> deviceStateInfos = new List<DeviceStateInfo>();
        public static List<QueryInfoReturnData> device_list = new List<QueryInfoReturnData>();
        IWebSocketManage _manage;
        public static IWebSocketManage webSocketManage;
        public DeviceWebSocketMiddleware(RequestDelegate next, IWebSocketManage manage)
        {
            this._next = next;
            this._manage = manage;
            //this._manage.sockets = _sockets;
            webSocketManage = _manage;
        }
        public async Task Invoke(HttpContext context)
        {
            WebSocket currentSocket = null;
            try
            {
                if (!context.WebSockets.IsWebSocketRequest)
                {
                    await _next.Invoke(context);
                    return;
                }
                CancellationToken cancellationToken = context.RequestAborted;
                string client = context.Connection.RemoteIpAddress.ToString();
                LogHelper.Log(context.Connection.RemoteIpAddress.ToString());
                currentSocket = await context.WebSockets.AcceptWebSocketAsync();
                ClientProcess(client, currentSocket);
                //_sockets.Add(currentSocket);
                QueryDevice(currentSocket);
                while (!currentSocket.CloseStatus.HasValue)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        break;
                    }
                    string response = await ReceiveStringAsync(currentSocket, cancellationToken);
                    if (response != null)
                    {
                        try
                        {
                            QueryInfo queryInfo = JsonConvert.DeserializeObject<QueryInfo>(response);
                            if (queryInfo != null)
                            {
                                if (queryInfo.method == "queryInfo")
                                {
                                    LogHelper.Log(response);
                                    QueryInfoReturn queryInfoReturn = JsonConvert.DeserializeObject<QueryInfoReturn>(response);
                                    if (queryInfoReturn != null)
                                    {
                                        string deviceno = string.Empty;
                                        foreach (var item in queryInfoReturn.data)
                                        {
                                            int index = device_list.FindIndex(x => x.deviceID == item.deviceID);
                                            bool result = false;
                                            if (index > -1)
                                            {
                                                QueryInfoReturnData queryInfoReturnData = device_list[index];
                                                if (queryInfoReturnData.deviceIP != item.deviceIP || queryInfoReturnData.liftMode != item.liftMode)
                                                {
                                                    result = DeviceProcess(item);
                                                    device_list[index] = item;
                                                }
                                            }
                                            else
                                            {
                                                result = DeviceProcess(item);
                                                device_list.Add(item);
                                            }
                                            if (result)
                                            {
                                                int socket_index = _sockets.FindIndex(n => n.DeviceIds == item.deviceID);
                                                if (socket_index > -1)
                                                {
                                                    _sockets[socket_index].Socket = currentSocket;
                                                }
                                                else
                                                {
                                                    SocketList socketList = new SocketList();
                                                    socketList.Socket = currentSocket;
                                                    socketList.DeviceIds = item.deviceID;
                                                    _sockets.Add(socketList);
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (queryInfo.method == "savePerson")
                                {
                                    LogHelper.Log(response);
                                    SavePersonReturn queryInfoReturn = JsonConvert.DeserializeObject<SavePersonReturn>(response);
                                    if (queryInfoReturn != null)
                                    {
                                        if (queryInfoReturn.data != null)
                                        {
                                            foreach (var item in queryInfoReturn.data)
                                            {
                                                if (item.errNo == 0)
                                                {
                                                    if (!string.IsNullOrEmpty(item.deviceName))
                                                    {
                                                        bool result = UpdateVoucherState(item.personID, item.deviceID, item.deviceName);
                                                    }
                                                    else
                                                    {
                                                        bool result = UpdateVoucherState(item.personID, item.deviceID);
                                                    }
                                                }

                                            }
                                        }

                                    }
                                }
                                else if (queryInfo.method == "delPerson")
                                {
                                    LogHelper.Log(response);
                                    SavePersonReturn queryInfoReturn = JsonConvert.DeserializeObject<SavePersonReturn>(response);
                                    if (queryInfoReturn != null)
                                    {
                                        foreach (var item in queryInfoReturn.data)
                                        {
                                            if (item.errNo == 0 || item.errNo == 503)
                                            {
                                                if (!string.IsNullOrEmpty(item.deviceName))
                                                {
                                                    bool result = DeleteVoucher(item.personID, item.deviceID, item.deviceName);
                                                }
                                                else
                                                {
                                                    bool result = DeleteVoucher(item.personID, item.deviceID);
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (queryInfo.method == "clearPerson")
                                {
                                    LogHelper.Log(response);
                                    ClearPersonReturn queryInfoReturn = JsonConvert.DeserializeObject<ClearPersonReturn>(response);
                                    if (queryInfoReturn != null)
                                    {
                                        foreach (var item in queryInfoReturn.data)
                                        {
                                            if (item.errNo == 0 || item.errNo == 503)
                                            {
                                                if (!string.IsNullOrEmpty(item.deviceName))
                                                {
                                                    bool result = ClearVoucher(item.deviceID, item.deviceName);
                                                }
                                                else
                                                {
                                                    bool result = ClearVoucher(item.deviceID);
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (queryInfo.method == "devState")
                                {
                                    LogHelper.Log(client + "发送" + response);
                                    devState state = JsonConvert.DeserializeObject<devState>(response);
                                    if (state != null)
                                    {
                                        DeviceStateProcess(state);
                                    }
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                }
                if (currentSocket != null && currentSocket.CloseStatus != null)
                    await currentSocket.CloseAsync(currentSocket.CloseStatus.Value, currentSocket.CloseStatusDescription, CancellationToken.None);
            }
            catch (Exception e)
            {
                if (currentSocket != null)
                {
                    if (_sockets != null && _sockets.Count > 0)
                    {
                        SocketList socket = _sockets.FirstOrDefault(n => n.Socket == currentSocket);
                        if (socket != null)
                        {
                            DeviceDAL deviceDAL = new DeviceDAL();
                            bool result = deviceDAL.BatchDelDeviceIds(socket.DeviceIds);
                            if (result)
                            {
                                LogHelper.Log("设备" + socket.DeviceIds + "WebSocket异常，设备状态更新为离线");
                                //_sockets.RemoveAll(n => n.Socket == currentSocket);
                            }
                        }
                    }
                }
            }
        }

        public void ClientProcess(string clientip, WebSocket currentSocket)
        {
            int index = clientSockets.FindIndex(x => x.ClientIP == clientip);
            if (index > -1)
            {
                clientSockets[index].Socket = currentSocket;
            }
            else
            {
                ClientSocket clientSocket = new ClientSocket();
                clientSocket.ClientIP = clientip;
                clientSocket.Socket = currentSocket;
                clientSockets.Add(clientSocket);
            }
        }

        public void DeviceStateProcess(devState state)
        {
            foreach (var item_state in state.data)
            {
                try
                {
                    if (string.IsNullOrEmpty(item_state.deviceName))
                    {
                        int deviceState_index = deviceStateInfos.FindIndex(n => n.deviceID == item_state.deviceID && n.deviceIP == item_state.deviceIP);

                        if (deviceState_index > -1)
                        {
                            if (deviceStateInfos[deviceState_index].deviceState != item_state.deviceState)
                            {
                                string dev_state = "离线";
                                if (item_state.deviceState == 4 || item_state.deviceState == 5)
                                {
                                    dev_state = "在线";
                                }
                                string contrl_state = "离线";
                                if (item_state.deviceState == 1 || item_state.deviceState == 4 || item_state.deviceState == 6)
                                {
                                    contrl_state = "在线";
                                }
                                UpdateDeviceState(dev_state, item_state.deviceID, item_state.deviceIP, contrl_state);
                                //deviceStateInfos.Remove(deviceState);
                                //deviceStateInfos.Add(item_state);
                            }
                            deviceStateInfos[deviceState_index] = item_state;
                        }
                        else
                        {
                            string dev_state = "离线";
                            if (item_state.deviceState == 4 || item_state.deviceState == 5)
                            {
                                dev_state = "在线";
                            }
                            string contrl_state = "离线";
                            if (item_state.deviceState == 1 || item_state.deviceState == 4 || item_state.deviceState == 6)
                            {
                                contrl_state = "在线";
                            }
                            deviceStateInfos.Add(item_state);
                            UpdateDeviceState(dev_state, item_state.deviceID, item_state.deviceIP, contrl_state);
                        }
                    }
                    else
                    {
                        int deviceState_index = deviceStateInfos.FindIndex(n => n.deviceID == item_state.deviceID && n.deviceIP == item_state.deviceIP && n.deviceName == item_state.deviceName);

                        if (deviceState_index > -1)
                        {
                            if (deviceStateInfos[deviceState_index].deviceState != item_state.deviceState)
                            {
                                string dev_state = "离线";
                                if (item_state.deviceState == 4 || item_state.deviceState == 5)
                                {
                                    dev_state = "在线";
                                }
                                string contrl_state = "离线";
                                if (item_state.deviceState == 1 || item_state.deviceState == 4 || item_state.deviceState == 6)
                                {
                                    contrl_state = "在线";
                                }
                                UpdateDeviceState(dev_state, item_state.deviceID, item_state.deviceIP, contrl_state, item_state.deviceName);
                            }
                            deviceStateInfos[deviceState_index] = item_state;
                        }
                        else
                        {
                            string dev_state = "离线";
                            if (item_state.deviceState == 4 || item_state.deviceState == 5)
                            {
                                dev_state = "在线";
                            }
                            string contrl_state = "离线";
                            if (item_state.deviceState == 1 || item_state.deviceState == 4 || item_state.deviceState == 6)
                            {
                                contrl_state = "在线";
                            }
                            deviceStateInfos.Add(item_state);
                            UpdateDeviceState(dev_state, item_state.deviceID, item_state.deviceIP, contrl_state, item_state.deviceName);
                        }
                    }

                }
                catch
                {

                }
            }
        }
        public static async Task<string> ReceiveStringAsync(WebSocket socket, CancellationToken ct)
        {
            var buffer = new ArraySegment<byte>(new byte[4 * 1024]);
            using (var ms = new MemoryStream())
            {
                WebSocketReceiveResult result;
                do
                {
                    ct.ThrowIfCancellationRequested();
                    try
                    {
                        result = await socket.ReceiveAsync(buffer, ct);
                        ms.Write(buffer.Array, buffer.Offset, result.Count);
                    }
                    catch (Exception e) { return null; }
                }
                while (!result.EndOfMessage);
                ms.Seek(0, SeekOrigin.Begin);
                if (result.MessageType != WebSocketMessageType.Text)
                {
                    return null;
                }
                using (var reader = new StreamReader(ms, Encoding.UTF8))
                {
                    return await reader.ReadToEndAsync();
                }
            }
        }

        public bool DeviceProcess(QueryInfoReturnData queryInfoReturnData)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.UpdateThirdPartyDevice(queryInfoReturnData);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool UpdateVoucherState(string personid, string deviceid)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.UpdateVoucherState(personid, deviceid);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool UpdateVoucherState(string personid, string deviceid, string devivename)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.UpdateVoucherState(personid, deviceid, devivename);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool DeleteVoucher(string personid, string deviceid)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.DeleteVoucher(personid, deviceid);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool DeleteVoucher(string personid, string deviceid, string devicename)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.DeleteVoucher(personid, deviceid, devicename);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool ClearVoucher(string deviceid)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.ClearVoucher(deviceid);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool ClearVoucher(string deviceid, string devicename)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.ClearVoucher(deviceid, devicename);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool UpdateDeviceState(string state, string deviceno, string deviceip, string control)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.UpdateDeviceState(state, deviceip, deviceno, control);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool UpdateDeviceState(string state, string deviceno, string deviceip, string control, string devicename)
        {
            DeviceDAL deviceDAL = new DeviceDAL();
            try
            {
                bool result = deviceDAL.UpdateDeviceState(state, deviceip, deviceno, control, devicename);
            }
            catch
            {
                return false;
            }

            return true;
        }

        public bool QueryDevice(WebSocket webSocket)
        {
            try
            {
                QueryInfo queryInfo = new QueryInfo();
                queryInfo.method = "queryInfo";
                Random random = new Random();
                queryInfo.req_id = random.Next();
                string web = webSocket.State.ToString();
                if (webSocket.State != WebSocketState.Closed)//连通状态才允许发送
                {
                    LogHelper.Log(JsonConvert.SerializeObject(queryInfo));
                    var array = new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(queryInfo)));
                    webSocket.SendAsync(array, WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        public static async Task<bool> SendMsg(string Msg)
        {
            foreach (var item in _sockets)
            {
                try
                {
                    if (item.Socket.State == WebSocketState.Closed)
                    {
                        DeviceDAL deviceDAL = new DeviceDAL();
                        bool result = deviceDAL.BatchDelDeviceIds(item.DeviceIds);
                        if (result)
                        {
                            int index = deviceStateInfos.FindIndex(x => x.deviceID == item.DeviceIds);
                            deviceStateInfos.RemoveAt(index);
                            LogHelper.Log("设备" + item.DeviceIds + "WebSocket断开，设备状态更新为离线，状态：" + item.Socket.State.ToString());
                            //_sockets.Remove(item);
                        }
                    }
                    else
                    {
                        byte[] bMessage = Encoding.UTF8.GetBytes(Msg);
                        await item.Socket.SendAsync(new ArraySegment<byte>(bMessage), WebSocketMessageType.Text, true, new CancellationToken());
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Log("消息发送异常:设备" + item.DeviceIds + ex.ToString());
                    continue;
                }
            }
            return true;
        }

        public static async Task<bool> NewSendMsg(string Msg)
        {
            foreach (var item in clientSockets)
            {
                try
                {
                    byte[] bMessage = Encoding.UTF8.GetBytes(Msg);
                    await item.Socket.SendAsync(new ArraySegment<byte>(bMessage), WebSocketMessageType.Text, true, new CancellationToken());
                }
                catch (Exception ex)
                {
                    LogHelper.Log("消息发送异常:设备" + item.ClientIP + ex.ToString());
                    continue;
                }
            }
            return true;
        }

        public bool SetParameter(WebSocket webSocket, List<QueryInfoReturnData> data)
        {
            ParameterInfo parameterInfo = new ParameterInfo();
            List<ParameterInfoData> list_device = new List<ParameterInfoData>();
            parameterInfo.method = "setParameter";
            Random random = new Random();
            parameterInfo.req_id = random.Next();
            DeviceDAL deviceDAL = new DeviceDAL();
            foreach (var item in data)
            {
                List<ElevatorInfo> elevatorInfos = deviceDAL.QueryEleByDeviceNo(item.deviceID);
                ParameterInfoData parameterInfoData = new ParameterInfoData();
                parameterInfoData.deviceID = item.deviceID;
                parameterInfoData.devRestart = 0;
                parameterInfoData.stateIntervalTime = 60;
                parameterInfoData.eventReportEnabled = 0;
                if (elevatorInfos != null && elevatorInfos.Count > 0)
                {
                    parameterInfoData.liftMode = elevatorInfos[0].Workmode;
                }
                else
                {
                    parameterInfoData.liftMode = 0;
                }

                parameterInfoData.devDateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                list_device.Add(parameterInfoData);
            }

            parameterInfo.data = list_device;

            if (webSocket.State != WebSocketState.Closed)//连通状态才允许发送
            {
                LogHelper.Log(JsonConvert.SerializeObject(parameterInfo));
                var array = new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(parameterInfo)));
                webSocket.SendAsync(array, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            return true;
        }

        public class SocketList
        {
            public WebSocket Socket { get; set; }
            public string DeviceIds { get; set; }
        }

        public class ClientSocket
        {
            public string ClientIP { get; set; }
            public WebSocket Socket { get; set; }
            public DateTime dateTime { get; set; } = DateTime.Now;
        }
    }
}
